package http

import (
	"github.com/edgexfoundry/edgex-go/internal/app/core/metadata/application"
	"github.com/edgexfoundry/edgex-go/internal/app/dtos"
	"github.com/edgexfoundry/edgex-go/internal/app/dtos/requests"
	"github.com/edgexfoundry/edgex-go/internal/app/dtos/responses"
	metadataContainer "github.com/edgexfoundry/edgex-go/internal/core/metadata/container"
	"github.com/edgexfoundry/edgex-go/internal/io"
	"github.com/edgexfoundry/edgex-go/internal/pkg"
	"github.com/edgexfoundry/edgex-go/internal/pkg/correlation"
	"github.com/edgexfoundry/edgex-go/internal/pkg/utils"
	"github.com/edgexfoundry/go-mod-bootstrap/v2/bootstrap/container"
	"github.com/edgexfoundry/go-mod-bootstrap/v2/di"
	"github.com/edgexfoundry/go-mod-core-contracts/v2/common"
	commonDTO "github.com/edgexfoundry/go-mod-core-contracts/v2/dtos/common"
	"github.com/gorilla/mux"
	"math"
	"net/http"
)

type ProductController struct {
	reader io.DtoReader
	dic    *di.Container
}

func NewProductController(dic *di.Container) *ProductController {
	return &ProductController{
		reader: io.NewJsonDtoReader(),
		dic:    dic,
	}
}

func (pc *ProductController) AddProduct(w http.ResponseWriter, r *http.Request) {
	if r.Body != nil {
		defer func() { _ = r.Body.Close() }()
	}

	lc := container.LoggingClientFrom(pc.dic.Get)

	ctx := r.Context()
	correlationId := correlation.FromContext(ctx)

	var reqDTOs []requests.AddProductRequest
	err := pc.reader.Read(r.Body, &reqDTOs)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	products := requests.AddProductReqToProductModels(reqDTOs)

	var addResponses []interface{}
	for i, p := range products {
		var response interface{}
		reqId := reqDTOs[i].RequestId
		newId, err := application.AddProduct(p, ctx, pc.dic)
		if err != nil {
			lc.Error(err.Error(), common.CorrelationHeader, correlationId)
			lc.Debug(err.DebugMessages(), common.CorrelationHeader, correlationId)
			response = commonDTO.NewBaseResponse(
				reqId,
				err.Message(),
				err.Code())
		} else {
			response = commonDTO.NewBaseWithIdResponse(
				reqId,
				"",
				http.StatusCreated,
				newId)
		}
		addResponses = append(addResponses, response)
	}

	utils.WriteHttpHeader(w, ctx, http.StatusMultiStatus)
	pkg.EncodeAndWriteResponse(addResponses, w, lc)
}

/**
 * @Description 产品查询
 * @method
 * @auth kely
 * @Date
 * @Param
 * @return
 **/

func (pc *ProductController) AllProducts(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()
	config := metadataContainer.ConfigurationFrom(pc.dic.Get)

	offset, limit, _, err := utils.ParseGetAllObjectsRequestQueryString(r, 0, math.MaxInt32, -1, config.Service.MaxResultCount)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	name := utils.ParseQueryStringToString(r, "name", "")
	groupId := utils.ParseQueryStringToString(r, "groupId", "")
	if name != "" {
		products, totalCount, err := application.ProductsByName(offset, limit, name, groupId, pc.dic)
		if err != nil {
			utils.WriteErrorResponse(w, ctx, lc, err, "")
			return
		}
		response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
		utils.WriteHttpHeader(w, ctx, http.StatusOK)
		pkg.EncodeAndWriteResponse(response, w, lc)

	} else {
		products, totalCount, err := application.AllProducts(offset, limit, groupId, pc.dic)
		if err != nil {
			utils.WriteErrorResponse(w, ctx, lc, err, "")
			return
		}
		response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
		utils.WriteHttpHeader(w, ctx, http.StatusOK)
		pkg.EncodeAndWriteResponse(response, w, lc)
	}
}

/**
 * @Description 产品查询所有
 * @method
 * @auth kely
 * @Date
 * @Param
 * @return
 **/

func (pc *ProductController) OwnProducts(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()

	products, totalCount, err := application.OwnProducts(pc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

//func (pc *ProductController) ProductByName(w http.ResponseWriter, r *http.Request) {
//	lc := container.LoggingClientFrom(pc.dic.Get)
//	ctx := r.Context()
//
//	vars := mux.Vars(r)
//	name := vars["name"]
//
//	//application.ProductByName(name, pc.dic)
//	product, err := application.ProductByName(name, pc.dic)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//
//	response := responses.NewProductResponse("", "", http.StatusOK, product)
//	utils.WriteHttpHeader(w, ctx, http.StatusOK)
//	pkg.EncodeAndWriteResponse(response, w, lc)
//}

func (pc *ProductController) ProductById(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()

	vars := mux.Vars(r)
	id := vars["id"]

	product, err := application.ProductById(id, pc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := responses.NewProductResponse("", "", http.StatusOK, product)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (pc *ProductController) ProductDelete(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()

	vars := mux.Vars(r)
	productId := vars["productid"]

	err := application.ProductDelete(productId, pc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := commonDTO.NewBaseResponse("", "", http.StatusOK)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (pc *ProductController) ProductUpdate(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()

	var reqDTOs requests.UpdateProductRequest
	err := pc.reader.Read(r.Body, &reqDTOs)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}

	product := dtos.ToProductModel(reqDTOs.Product)
	err = application.ProductUpdate(product, ctx, pc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := commonDTO.NewBaseResponse("", "", http.StatusOK)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

func (pc *ProductController) ProductProfileByProductId(w http.ResponseWriter, r *http.Request) {
	lc := container.LoggingClientFrom(pc.dic.Get)
	ctx := r.Context()

	vars := mux.Vars(r)
	productId := vars["productid"]

	productProfile, err := application.ProductProfileByProductId(productId, pc.dic)
	if err != nil {
		utils.WriteErrorResponse(w, ctx, lc, err, "")
		return
	}
	response := responses.NewProductProfileResponse("", "", http.StatusOK, productProfile)
	utils.WriteHttpHeader(w, ctx, http.StatusOK)
	pkg.EncodeAndWriteResponse(response, w, lc)
}

//func (pc *ProductController) ProductsByName(w http.ResponseWriter, r *http.Request) {
//	lc := container.LoggingClientFrom(pc.dic.Get)
//	ctx := r.Context()
//	config := metadataContainer.ConfigurationFrom(pc.dic.Get)
//
//	vars := mux.Vars(r)
//	name := vars["name"]
//
//	offset, limit, _, err := utils.ParseGetAllObjectsRequestQueryString(r, 0, math.MaxInt32, -1, config.Service.MaxResultCount)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//
//	//application.ProductByName(name, pc.dic)
//	products, totalCount, err := application.ProductsByName(offset, limit, name, pc.dic)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//
//	response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
//	utils.WriteHttpHeader(w, ctx, http.StatusOK)
//	pkg.EncodeAndWriteResponse(response, w, lc)
//}

//func (pc *ProductController) ProductsByGroupId(w http.ResponseWriter, r *http.Request) {
//	lc := container.LoggingClientFrom(pc.dic.Get)
//	ctx := r.Context()
//	config := metadataContainer.ConfigurationFrom(pc.dic.Get)
//
//	vars := mux.Vars(r)
//	groupId := vars["groupid"]
//
//	offset, limit, _, err := utils.ParseGetAllObjectsRequestQueryString(r, 0, math.MaxInt32, -1, config.Service.MaxResultCount)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//	products, totalCount, err := application.ProductsByGroupId(groupId, offset, limit, pc.dic)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//	response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
//	utils.WriteHttpHeader(w, ctx, http.StatusOK)
//	pkg.EncodeAndWriteResponse(response, w, lc)
//}

//func (pc *ProductController) AllProductsWithDeviceNum(w http.ResponseWriter, r *http.Request) {
//	lc := container.LoggingClientFrom(pc.dic.Get)
//	ctx := r.Context()
//	config := metadataContainer.ConfigurationFrom(pc.dic.Get)
//
//	offset, limit, _, err := utils.ParseGetAllObjectsRequestQueryString(r, 0, math.MaxInt32, -1, config.Service.MaxResultCount)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//	products, totalCount, err := application.AllProductsWithDeviceNum(offset, limit, pc.dic)
//	if err != nil {
//		utils.WriteErrorResponse(w, ctx, lc, err, "")
//		return
//	}
//	response := responses.NewMultiProductsResponse("", "", http.StatusOK, totalCount, products)
//	utils.WriteHttpHeader(w, ctx, http.StatusOK)
//	pkg.EncodeAndWriteResponse(response, w, lc)
//}
